﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using MSWMDMLib;
using FireZone.NativeWMDMInteface;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Schedulers;
using System.ComponentModel;
using System.Windows;
using MS.WindowsAPICodePack.Internal;

namespace FireZone.DataStructure
{
    internal class MTPDeviceItem : IDisposable, INotifyPropertyChanged
    {
        private String _deviceName;
        private String _deviceManufacturer;
        private uint? _deviceVersion;
        private WMDMDeviceType? _deviceType;
        private PowerSource _devicePowerSource;
        private uint? _deviceStatus;
        private uint? _deviceIcon;
        private _WAVEFORMATEX[] _deviceWaveFormat;
        private String[] _deviceMimeType;
        private ObservableCollection<MTPStorageItem> _deviceStorages;

        public String DeviceName { get; set; }
        public String DeviceManufacturer { get; set; }
        public uint DeviceVersion { get; set; }
        public WMDMDeviceType? DeviceType
        {
            get
            {
                uint uValue;
                DeviceItem.GetType(out uValue);
                _deviceType = (WMDMDeviceType)uValue;

                return _deviceType;
            }
            set
            {
                _deviceType = value;
            }
        }
        public PowerSource DevicePowerSource
        {
            get
            {
                if (_devicePowerSource == null)
                {
                    PowerSource ps = new PowerSource();
                    uint powerSrc = 0;
                    uint powerRemaining = 0;
                    DeviceItem.GetPowerSource(out powerSrc, out powerRemaining);
                    ps.devicePowerSource = (WMDMPowerSource)powerSrc;
                    ps.devicePowerPercentRemaining = powerRemaining;
                    _devicePowerSource = ps;
                }
                return _devicePowerSource;
            }
            set
            {
                _devicePowerSource = value;
            }
        }
        public uint? deviceStatus { get; set; }
        public uint? deviceIcon { get; set; }
        public _WAVEFORMATEX[] deviceWaveFormat { get; set; }
        public String[] deviceMimeType { get; set; }
        public String deviceCanonicalName { get; set; }
        public ObservableCollection<MTPStorageItem> deviceStorages
        {
            get
            {
                if (_deviceStorages == null)
                {
                    WMDMDeviceType uValue = DeviceType.Value;
                    _deviceStorages = new ObservableCollection<MTPStorageItem>();
                    WMDMStorageEnum wmdmStgEnum;
                    DeviceItem.EnumStorage(out wmdmStgEnum);
                    WMDMStorage wmdmStg;
                    uint uFeteched;
                    while (true)
                    {
                        wmdmStgEnum.Next(1, out wmdmStg, out uFeteched);
                        if (uFeteched == 0) break;
                        IWMDMStorage3 wmdmStgV3 = (IWMDMStorage3)wmdmStg;
                        //                            WMDM_STORAGE_ENUM_MODE enumMode = WMDM_STORAGE_ENUM_MODE.ENUM_MODE_METADATA_VIEWS;
                        //                            wmdmStgV3.SetEnumPreference(out enumMode, 0, null);
                        _deviceStorages.Add(new MTPStorageItem() { StorageItem = (IWMDMStorage3)wmdmStg, });
                    }
                }
                return _deviceStorages;
            }
            set
            {
                _deviceStorages = value;
            }
        }
        private IWMDMDevice3 _devItem;
        public IWMDMDevice3 DeviceItem
        {
            get
            {
                return _devItem;

            }
            set
            {
                StringBuilder strValue = new StringBuilder(1024);
                _devItem = value;
                _devItem.GetCanonicalName(strValue, (uint)strValue.Capacity);
                deviceCanonicalName = strValue.ToString();

                _devItem.GetName(strValue, (uint)strValue.Capacity);
                DeviceName = strValue.ToString();

                _devItem.GetManufacturer(strValue, (uint)strValue.Capacity);
                DeviceManufacturer = strValue.ToString();
           }
        }

        public Dictionary<string, object> DeviceProperties { get; set; }

        public static void RenewCancellationTokenSource(MTPDeviceItem devitem)
        {
            if(devitem != null) Interlocked.Exchange<CancellationTokenSource>(ref devitem.CancellationTokenSource, new CancellationTokenSource()).SafeCancelCancellationTokenSource();
        }

        private CancellationTokenSource CancellationTokenSource;
        private QueuedTaskScheduler _operationTaskScheduler;
        private int _taskCount;

        public CancellationToken CancellationToken
        { 
            get
            {
                if (CancellationTokenSource == null) RenewCancellationTokenSource(this);
                return CancellationTokenSource.Token;
            }
        }

        public TaskScheduler OperationTaskScheduler
        {
            get
            {
                if (_operationTaskScheduler == null)
                {
                    _operationTaskScheduler = new QueuedTaskScheduler(1, DeviceName + " OperationTaskScheduler");
                    _operationTaskScheduler.QueuedTaskCountChanged += new EventHandler<QueuedTaskCountChangedEventArgs>((obj, e) => { TaskCount = e.Count; });                        
                }
                return _operationTaskScheduler;
            }
        }

        public string ToolTipText 
        { 
            get
            {
                return _toolTipText;
            }
            set
            {
                if (!string.Equals(_toolTipText, value, StringComparison.Ordinal))
                {
                    _toolTipText = value;
                    PropertyChanged.NotifyPropertyChangedAsync(this, "ToolTipText");
                }
            }
        }

        public bool HasTask
        {
            get
            {
                return _hasTask;
            }
            set
            {
                if(_hasTask != value)
                {
                    _hasTask = value;
                    PropertyChanged.NotifyPropertyChangedAsync(this, "HasTask");
                }
            }
        }

        public int TaskCount 
        { 
            get
            {
                return _taskCount;
            }
            private set
            {
                if (_taskCount != value)
                {
                    _taskCount = value;
                    PropertyChanged.NotifyPropertyChangedAsync(this, "TaskCount");
                    HasTask = _taskCount > 0;
                }
            }
        }

        private void ThrowIfDisposed()
        {
            if (_disposed) throw new ObjectDisposedException("MTPDeviceItem");
        }

        #region IDisposable Members

        public void Dispose()
        {
            CancellationTokenSource.SafeCancelCancellationTokenSource();
            _operationTaskScheduler.SafeDispose();
            _disposed = true;
        }

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        private string _toolTipText;
        private bool _hasTask;
        private bool _disposed;

        #endregion
    }
}
